﻿Imports System.Collections

Namespace DoFactory.GangOfFour.Interpreter.RealWorld2

    Public Class Program

        Public Shared Sub Main()
            Dim tokenString As String = "+ - 10 2 3"
            Dim tokenList As New List(Of String)(tokenString.Split(" "c))

            Dim expression As IExpression = New TokenReader().ReadToken(tokenList)
            Console.WriteLine(expression.Interpret())
            ' (10 - 2) + 3 = 11
            tokenString = "- + 10 5 - 8 2"
            tokenList = New List(Of String)(tokenString.Split(" "c))

            expression = New TokenReader().ReadToken(tokenList)
            Console.WriteLine(expression.Interpret())
            ' (10 + 5) - (8 - 2) = 9
        End Sub

    End Class

    Public Interface IExpression
        Function Interpret() As Integer
    End Interface

    'terminal expression
    Public Class NumberExpression
        Implements IExpression
        Private number As Integer
        Public Sub New(ByVal i As Integer)
            number = i
        End Sub

        Private Function IExpression_Interpret() As Integer Implements IExpression.Interpret
            Return number
        End Function
    End Class

    'nonterminal expression, contains left and right expressions below it
    Public Class AddExpression
        Implements IExpression
        Private leftExpression As IExpression
        Private rightExpression As IExpression

        Public Sub New(ByVal left As IExpression, ByVal right As IExpression)
            leftExpression = left
            rightExpression = right
        End Sub

        Private Function IExpression_Interpret() As Integer Implements IExpression.Interpret
            Return leftExpression.Interpret() + rightExpression.Interpret()
        End Function
    End Class

    'nonterminal expression, contains left and right expressions below it
    Public Class SubtractExpression
        Implements IExpression
        Private leftExpression As IExpression
        Private rightExpression As IExpression

        Public Sub New(ByVal left As IExpression, ByVal right As IExpression)
            leftExpression = left
            rightExpression = right
        End Sub

        Private Function IExpression_Interpret() As Integer Implements IExpression.Interpret
            Return leftExpression.Interpret() - rightExpression.Interpret()
        End Function
    End Class

    Public Class TokenReader
        Public Function ReadToken(ByVal tokenList As List(Of String)) As IExpression
            Return ReadNextToken(tokenList)
        End Function

        Private Function ReadNextToken(ByVal tokenList As List(Of String)) As IExpression
            Dim i As Integer
            If Integer.TryParse(tokenList.First(), i) Then
                'if the token is integer (terminal)
                tokenList.RemoveAt(0)
                'process terminal expression
                Return New NumberExpression(i)
            Else
                'process nonTerminal expression
                Return ReadNonTerminal(tokenList)
            End If
        End Function

        Private Function ReadNonTerminal(ByVal tokenList As List(Of String)) As IExpression
            Dim token As String = tokenList.First()
            tokenList.RemoveAt(0)
            'read the symbol
            Dim left As IExpression = ReadNextToken(tokenList)
            'read left expression
            Dim right As IExpression = ReadNextToken(tokenList)
            'read right expression
            If token = "+" Then
                Return New AddExpression(left, right)
            ElseIf token = "-" Then
                Return New SubtractExpression(left, right)
            End If
            Return Nothing
        End Function
    End Class

End Namespace
